#pragma once
  
#define RESOURCE_BASE_PATH "" 

namespace Melting
{ 
	typedef String	ResourceID;

	typedef UINT16	UID;
	
//		class IResourceInstance;

	/**
		Template class for a Resource !
	*/
	template < class TData, class TID >
	class IResource
	{
		static const UID INVALID_UID = 0xFFFF;


	public:
		/// CTOR
		inline	IResource( UID _UID = INVALID_UID );
		/// DTOR
		inline ~IResource( void );

		/// Initialize
		inline bool								Initialize			( const TID& _rID );
		/// Release
		inline void								Release				( void );
		/// Is Initialized
		inline bool								IsInitialized		( void ) const;

		/// Specify wether it is initialized or not
		inline void								SetInitialized		( bool _bIsInitialized );	

		/// Get the ID
		inline const TID&						GetID				( void ) const;
		/// Get the actual Resource
		inline TData&							GetData				( void );

		/// Get the number of IResourceInstance bound to this IResource 
		inline ULONG							GetNbInstances		( void ) const; 
		/// Add the given IResourceInstance to the list of the bound IResourceInstances 
		inline void								RegisterInstance	( IResourceInstance< IResource >& _rInstance ); 
		/// Remove the given IResourceInstance from the list of the bound IResourceInstances 
		inline void								UnregisterInstance	( IResourceInstance< IResource >& _rInstance ); 

		/// Get the last time the file has been written
		inline const SystemTime&				GetLastWriteTime	( void ) const;
		/// Reload the Resource specifying the updated last write time
		void									Reload				( const SystemTime& _rLastWriteTime, const TID& _rDefaultResourceID );


		/// Get the internal Unique ID
		inline const UID&						GetUID			( void ) const;

		/// Specify the ID 
		inline void								SetID			( const TID& _rID );

	protected: 		 

		/// Specify an internal Unique ID
		inline void								SetUID			( const UID& _rUID );



		bool										mbIsInitialized;			///< Has this Resource been Initialized ?
		UID											mUID;
		TID											mID;						///< ID of this Resource
		TData										mData;						///< Retource data
		List< IResourceInstance< IResource >* >		mlBoundInstances;			///< List of all IResourceInstance bound to this IResource
		SystemTime									mLastWriteTime;				///< Last time this resource was modified! --- within the filesystem !
	};

	//------------------------------------------------------------------
	// CTOR
	//------------------------------------------------------------------
	template< class TData, class TID >
	IResource< TData, TID >::IResource( UID _UID )
	:	mbIsInitialized ( false ) 
	,	mUID			( _UID )
	,	mID				()
	{
	}

	//------------------------------------------------------------------
	// DTOR
	//------------------------------------------------------------------
	template< class TData, class TID >
	IResource< TData, TID >::~IResource( void )
	{			
		MB_ASSERT_IS_NOT_INITIALIZED( "Resource has not been properly Released\n" );
	}
	
	//------------------------------------------------------------------
	// 
	//------------------------------------------------------------------
	template< class TData, class TID >
	bool IResource< TData, TID >::Initialize( const TID& _rID )
	{
		//--------------------------
		// precondition
		MB_ASSERT_IS_NOT_INITIALIZED();  
		//--------------------------

		GetSystemTime( & mLastWriteTime ) ;

		bool bSuccess = mData.Initialize( _rID );
		
		SetInitialized( bSuccess );

		return bSuccess;
	}
	
	//------------------------------------------------------------------
	// 
	//------------------------------------------------------------------
	template< class TData, class TID >
	void IResource< TData, TID >::Release( void )
	{
		//--------------------------
		// precondition
		MB_ASSERT_IS_INITIALIZED();  
		//--------------------------

		mData.Release();
		SetInitialized( false );
	}

	//------------------------------------------------------------------
	// 
	//------------------------------------------------------------------
	template< class TData, class TID >
	bool IResource< TData, TID >::IsInitialized	( void ) const
	{
		return mbIsInitialized;
	}
	
	//------------------------------------------------------------------
	// 
	//------------------------------------------------------------------
	template< class TData, class TID >
	void IResource< TData, TID >::SetInitialized	( bool _bIsInitialized )
	{
		mbIsInitialized = _bIsInitialized;
	}
	
	//------------------------------------------------------------------
	// 
	//------------------------------------------------------------------
	template< class TData, class TID >
	void IResource< TData, TID >::SetID ( const TID& _rID )
	{
		mID = _rID;
	}

	//------------------------------------------------------------------
	// 
	//------------------------------------------------------------------
	template< class TData, class TID >
	void IResource< TData, TID >::SetUID ( const UID& _rUID )
	{
		mUID = _rUID;
	}

	//------------------------------------------------------------------
	// 
	//------------------------------------------------------------------
	template< class TData, class TID >
	TData& IResource< TData, TID >::GetData ( void )
	{
		return mData;
	}
	//------------------------------------------------------------------
	// 
	//------------------------------------------------------------------
	template< class TData, class TID >
	const TID& IResource< TData, TID >::GetID ( void ) const
	{
		return mID;
	}

	//------------------------------------------------------------------
	// Get the internal Unique ID
	//------------------------------------------------------------------
	template< class TData, class TID >
	const UID& IResource< TData, TID >::GetUID ( void ) const
	{
		return mUID;
	}

	// ------------------------------------------------------------------------------
	// Get the number of Instance bound to this resource 
	// ------------------------------------------------------------------------------
	template< class TData, class TID >
	ULONG IResource< TData, TID >::GetNbInstances	( void ) const
	{
		//-----------------------
		// precondition
		MB_ASSERT_IS_INITIALIZED();
		//-----------------------

		return mlBoundInstances.size();
	}
	
	// ------------------------------------------------------------------------------
	// Increment the counter of Instance using this resource
	// ------------------------------------------------------------------------------
	template< class TData, class TID >
	void IResource< TData, TID >::RegisterInstance( IResourceInstance< IResource >& _rInstance )
	{			
		//-----------------------
		// precondition
		MB_ASSERT_IS_INITIALIZED();
		//-----------------------

		mlBoundInstances.push_back( & _rInstance );
	}
	
	// ------------------------------------------------------------------------------
	// Decrement the counter of Instance using this resource
	// ------------------------------------------------------------------------------
	template< class TData, class TID >
	void IResource< TData, TID >::UnregisterInstance( IResourceInstance< IResource >& _rInstance )
	{
		//-----------------------
		// precondition
		MB_ASSERT_IS_INITIALIZED(); 
		MB_ASSERT( mlBoundInstances.end() != std::find( mlBoundInstances.begin(), mlBoundInstances.end() ,& _rInstance ), "Trying to remove an instance that was not bound !!\n" );
		//-----------------------
		
		mlBoundInstances.remove( & _rInstance );
	}   

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	template< class TData, class TID >
	const SystemTime& IResource< TData, TID >::GetLastWriteTime( void ) const
	{
		return mLastWriteTime;
	}

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	template< class TData, class TID >
	void IResource< TData, TID >::Reload( const SystemTime& _rLastWriteTime, const TID& _rDefaultResourceID  )
	{		
		mLastWriteTime = _rLastWriteTime;

		List< IResourceInstance< IResource >* > lInstancesToRebind = mlBoundInstances;

		LOG ( " nb %d\n" , mlBoundInstances.size() );

		for(	List< IResourceInstance< IResource >* >::iterator itInstance = lInstancesToRebind.begin() ; 
				itInstance != lInstancesToRebind.end(); 
				itInstance ++ )
		{
			(*itInstance)->UnbindFromResource() ;
		}
		LOG ( " nb %d\n" , mlBoundInstances.size() );

		Release();
		bool bSuccess = Initialize( GetID() );

		if( !bSuccess )
		{	
			LOG("-- Could not create the resource '%s'\n", GetID().c_str() );
		
			bSuccess = Initialize( _rDefaultResourceID );				

			MB_ASSERT( bSuccess , "--- Could not create the default resource '%s'\n", _rDefaultResourceID.c_str() );
		}
		
		for(	List< IResourceInstance< IResource >* >::iterator itInstance = lInstancesToRebind.begin() ; 
				itInstance != lInstancesToRebind.end(); 
				itInstance ++ )
		{ 
			(*itInstance)->BindToResource( *this ) ;
		}
		
		LOG ( " nb %d\n" , mlBoundInstances.size() );
	} 
}